<?php

require_once 'Pipes/Controller/ActionMapper.php';
require_once 'Pipes/FileSystem/File/Finder/AllProjects.php';
require_once 'Pipes/Model/Mapper.php';
require_once 'Pipes/User/AccessControl.php';
require_once 'Pipes/User/AccessControl/Array.php';
require_once 'Pipes/View.php';
require_once 'PipesImpl/Controller.php';
require_once 'PipesImpl/Nameable.php';
require_once 'PipesImpl/Route.php';
require_once 'PipesImpl/User/Credentials.php';

abstract class Pipes_Controller implements PipesImpl_Controller, PipesImpl_Nameable
{
	private $_data = array();
	private $_name = '';

	protected $_defaultAction = 'browse';
	protected $_actionMapper = null;
	protected $_config = null;
	protected $_currentCredentials = null;
	protected $_isAjax = false;
	protected $_route = null;
	protected $_view = null;
	protected $_doAuth = false;
	 
	public function __construct(PipesImpl_Config $config) 
	{
		$explodedName = explode('_', get_class($this));
		$name = substr(array_pop($explodedName), 0, -10);
		
		$this->_name = $name;
		
		$this->_view = new Pipes_View($config, "Views");
		$this->_view->controller = $this;
		$this->_view->requestUrl = $_SERVER['REQUEST_URI'];
		
		$this->_actionMapper = new Pipes_Controller_ActionMapper();
		$this->_config = $config;

		if ($this->_doAuth === true) {
			$finder = new Pipes_FileSystem_File_Finder_AllProjects($config);
			$permissionFile = $finder->find('permissions.php');
			$this->_doAuth = new Pipes_User_AccessControl(
				new Pipes_User_AccessControl_Array(require $permissionFile->fullPath)
			);
		}
	}
	
	public function run(PipesImpl_Route $route, PipesImpl_User_Credentials $credentials = null) {
		$this->_currentCredentials = $credentials;
		if ($this->_doAuth !== false && (is_null($credentials) || $this->_doAuth->can($credentials, $route) === false)) {
			$route = new Pipes_Route_Simple('Error', 'unauthorized', $route->extras);
			$this->_view->credentials = $credentials;
		}

		if (isset($route->extras) && isset($route->extras['isAjax'])) {
			$this->_isAjax = (bool)$route->extras['isAjax'];
			$this->_view->isAjax = $this->_isAjax;
			if ($this->_isAjax) {
				$this->_view->requestUrl = urlencode($_SERVER['HTTP_REFERER']);
			}
		}
		
		// upsupported hack - will disappear in the next revision when 
		// Controllers are rewritten
		$dispatched = $this->dispatch($route);
		if ($dispatched instanceof PipesImpl_Route) {
			$route = $dispatched;
		}
		
		if (!isset($this->title)) {
			$this->_set('title', ucwords("{$this->_name} :: {$this->_action}"));
		}
		
		if (!isset($route->action)) {
			$controllerResult = $this->_view->renderByRoute(
				new Pipes_Route_Simple(
					$route->controller,
					$this->_defaultAction,
					$route->extras,
					$route->page_type
				)
			);
		} else {
			$controllerResult = $this->_view->renderByRoute($route);
		}
		
		if ($this->_isAjax && !in_array($route->page_type, array('json', 'xml'))) {
			return $controllerResult;
		}
		if (!isset($route->page_type)) {
			return $controllerResult;
		}

		$pageTypeClass = 'Pipes_Controller_PageType_' . ucfirst($route->page_type);
		$finder = new Pipes_FileSystem_File_Finder($this);
		$finder->findByClass($pageTypeClass)->requireOnce();
		$pageType = new $pageTypeClass($this->_config, $this);
		return $pageType->render($controllerResult);
	}
	
	protected function dispatch(PipesImpl_Route $route) {
		$action = isset($route->action) ? $route->action : $this->_defaultAction;
		$mappedAction = $this->_actionMapper->map($action);

		$callback = array($this, $mappedAction);
		if (is_callable($callback)) {
			$extras = $route->extras;
			call_user_func_array($callback, $extras);
		}
	}
	
	/**
	 *
	 * Read-only version of setter that allows any value to be set on 
	 * this controller.
	 *
	 * Generally used for setting internal variables to pass off to wrappers
	 *
	 */
	protected function _set($key, $value) 
	{
		$this->_data[$key] = $value;
	}
	
	public function __set($key, $value) {
		throw new Pipes_Exception('Controller attributes are read-only');
	}

	public function __get($key) 
	{
		return $this->_data[$key];
	}
	
	public function __isset($key) 
	{
		return isset($this->_data[$key]);
	}

	public function getName() 
	{
		return $this->_name;
	}
}

